/*
 **********************************************************
 *
 * Programme :	parser.c
 *
 * ecrit par :	BAYRAMOV Matin & IBRAHIMLI Nihat
 *
 * resume : 		contient les fonctions utiles
 * 				pour la manupilation sur le fichier
 *
 * date :   		Feb 6, 2013
 *
 ***********************************************************
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "graphe.h"
#include "parser.h"


/*******************************************************************
 *
 * Fonction 	: 	findFirstElement
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 *
 * Retour 	:	line[i] une caratere
 *
 * Description 	: 	elle permet de recuperer le premier element de la ligne
 * 					sachant que on elimine des espace et des tabulations
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

char findFirstElement(char* line) {

	int i = 0;
	if (line[i] != 32 && line[i] != 9) {
		return line[i];
	} else {
		while (line[i] == 32 || line[i] == 9) {
			i++;
		}
		return line[i];
	}
}

/*******************************************************************
 *
 * Fonction 	: 	alphanumeric
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 			      int i  (l'indice de ligne que l'on va faire des traitement)		
 *
 * Retour 	:	COMMANDE_INVALIDE si on rencontre des anomaliees dans la ligne
 *  					i l'indice de ligne quand boucle s'arrete 
 *
 * Description 	: 	elle parcourt toutes les caracteres numeriques a partir de l'indice i en ligne
 * 
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int alphanumeric(char* line, int i) {

	// on doit avoir au moins d'une carectere numerique (47 < x < 58, code ascii)
	do {
		// si on rencontre une carectere non numerique
		if (line[i] < 48 || line[i] > 57) {
			return COMMANDE_INVALIDE;
		}
		i++;
	} while (line[i] > 47 && line[i] < 58);

	return i;
}

/*******************************************************************
 *
 * Fonction 	: 	spaceOrTabulation
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 			      int i  (l'indice de ligne que l'on va faire des traitement)		
 *
 * Retour 	:	COMMANDE_INVALIDE si on rencontre des anomaliees dans la ligne
 *  					i l'indice de ligne quand boucle s'arrete 
 *
 * Description 	: 	elle parcourt toutes les espaces et tabulations a partir de l'indice i en ligne
 * 
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int spaceOrTabulation(char* line, int i) {

	do {
		// on doit avoir au moins d'une caractere de l'espace ou bien la tabulation
		if (line[i] != 32 && line[i] != 9) {
			return COMMANDE_INVALIDE;
		}
		i++;
	} while (line[i] == 32 || line[i] == 9);

	return i;
}

/*******************************************************************
 *
 * Fonction 	: 	lineVerification
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 					
 *
 * Retour 	:	COMMANDE_INVALIDE si on rencontre des anomaliees dans la ligne
 *  					RES_OK si le resultat est OK
 *
 * Description 	: 	verifie la coherence des commandes dans la ligne nombre maximum de sommets 
 * 
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int maxVertexLineVerification(char* line) {
	int i = 0;

	// si on rencontre des espaces (32, code ascii) ou bien des tabulations (9, code ascii) on les elimine
	while (line[i] == 32 || line[i] == 9) {
		i++;
	}

	// verification des carecteres numeriques
	i = alphanumeric(line, i);
	if (i == COMMANDE_INVALIDE) {
		return COMMANDE_INVALIDE;
	}

	// si on rencontre des espaces ou bien des tabulations on les elimine
	while (line[i] == 32 || line[i] == 9) {
		if (line[i] != 32 && line[i] != 9) {
			return COMMANDE_INVALIDE;
		}
		i++;
	}

	// si c'est bien la fin de la ligne (10, code ascii)
	if (line[i] == 10) {
		return RES_OK;
	}

	return COMMANDE_INVALIDE;
}

/*******************************************************************
 *
 * Fonction 	: 	EdgeLineVerification
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 					
 * Retour 	:	COMMANDE_INVALIDE si on rencontre des anomaliees dans la ligne
 *  					RES_OK si le resultat est OK
 *
 * Description 	: 	la verification de la coherence des commandes dans la ligne de l'insertion des sommets et des aretes
 * 
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int EdgeVertexLineVerification(char* line) {

	int i = 0;
	int firstTime = 1;

	// si on rencontre des espaces (32, code ascii) ou bien des tabulations (9, code ascii) on les elimine
	while (line[i] == 32 || line[i] == 9) {
		i++;
	}

	// verification des carecteres numeriques
	i = alphanumeric(line, i);
	if (i == COMMANDE_INVALIDE) {
		return COMMANDE_INVALIDE;
	}

	// verification des espaces ou bien des tabulations
	i = spaceOrTabulation(line, i);
	if (i == COMMANDE_INVALIDE) {
		return COMMANDE_INVALIDE;
	}

	if (line[i] == 10 || line[i] != ':') {
		return COMMANDE_INVALIDE;
	}
	i++;
	if (line[i] == 10) {
		return RES_OK;
	}

	// verification des espaces ou bien des tabulations
	i = spaceOrTabulation(line, i);
	if (i == COMMANDE_INVALIDE) {
		return COMMANDE_INVALIDE;
	}

	if (line[i] == 10) {
		return RES_OK;
	}
	// si ce n'est pas encore la fin de la ligne
	do {

		// a partir de deuxime passage
		if (firstTime == 0) {
			i++;

			// verification des espaces ou bien des tabulations
			i = spaceOrTabulation(line, i);
			if (i == COMMANDE_INVALIDE) {
				return COMMANDE_INVALIDE;
			}
		}

		// si la caractere courant n'est pas (
		if (line[i] != '(') {
			return COMMANDE_INVALIDE;
		}

		i++;

		// verification des carecteres numeriques
		i = alphanumeric(line, i);
		if (i == COMMANDE_INVALIDE) {
			return COMMANDE_INVALIDE;
		}

		if (line[i] != '/') {
			return COMMANDE_INVALIDE;
		}
		i++;

		i = alphanumeric(line, i);
		if (i == COMMANDE_INVALIDE) {
			return COMMANDE_INVALIDE;
		}

		if (line[i] != ')') {
			return COMMANDE_INVALIDE;
		}

		i++;
		firstTime = 0;

	} while (line[i] == ',');

	if (line[i] == 10) {
		return RES_OK;
	}

	// verification des espaces ou bien des tabulations
	i = spaceOrTabulation(line, i);
	if (i == COMMANDE_INVALIDE) {
		return COMMANDE_INVALIDE;
	}
	if (line[i] != 10) {
		return COMMANDE_INVALIDE;
	}

	return RES_OK;
}

/*******************************************************************
 *
 * Fonction 	: 	stringToInt
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 					int from (à partir de l'index "from" de la line)
 char to (jusqu'au premier element "to" que l'on rencontre)
 *
 * Retour 	:	result le chiffre trouve 
 *
 * Description 	: 	fonction permet de transformer de caractères numeriques de la ligne "line", a partir de l'index i à un nombre entier.
 *   					La lecture de la chaine s'effectue jusqu'a le character "to".
 * 
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int stringToInt(char* line, int from, char to) {

	int i = from;
	int taille = 0;
	int result = 0;

	// permet de trouver combien caractères numeriques que l'on doit stocker 
	while (line[i] != to) {
		if (line[i] >= 48 && line[i] <= 57) {
			taille++;
		}
		i++;
	}

	char* numberString = NULL;
	numberString = (char*) calloc((taille + 1), sizeof(char));

	i = 0;
	while (line[from] != to) {

		// on enregistre des caracteres numerqiues dans le tableau	
		if (line[from] >= 48 && line[from] <= 57) {
			numberString[i] = line[from];
			i++;
		}
		from++;
	}
	result = strtol(numberString, NULL, 10);

	free(numberString);
	numberString = NULL;

	return result;
}

/*******************************************************************
 *
 * Fonction 	: 	edgeLoading
 *
 * Parametres 	: 	char* line  (la line courante du texte)
 * 					Graphe* G (le pointeur sur le graphe)
 *
 * Retour 	:		err si les erreurs produisent pendant insertionArete(..) ou bien
 * 					il y a des anomalies dans la fichier
 *						RES_OK si le resultat est OK
 *  	
 * Description 	: 	fonction permet de charger des aretes que l'on trouve.
 *
 * Complexité	:	O(n) - n le nombre de caractères de lus
 *
 */

int edgeLoading(char* line, Graphe* G) {

	int err;
	int voisin, poids;
	char c;
	int size;

	err = EdgeVertexLineVerification(line);
	if (err != RES_OK) {
		return err;
	}

	int sommet = stringToInt(line, 0, ':');
	char* chFinded = line;

	do {
		c = '(';

		// on lance une recherche de caractre "(" dans la ligne
		chFinded = strchr(chFinded, c);

		// s'il n'y a pas d'arete a insere, on peut avoir un tel sommet donc return RES_OK (ex 3 : )
		if (chFinded == NULL) {
			return RES_OK; // on quitte la methode	
		}
		c = '/';

		// on convert en entier le caractre trouvee a partir de l'indice 0 jusqu'a la caractre "/" dans la ligne
		voisin = stringToInt(chFinded, 0, c);
		chFinded = strchr(chFinded, c);
		c = ')';
		poids = stringToInt(chFinded, 0, c);

		// on insere une arete avec des valeurs trouvees
		err = insertionArete(G, sommet, voisin, poids, 'o');

		// si l'insertion ne passe pas bien
		if (err != RES_OK) {
			return err;
		}

		chFinded = strchr(chFinded, c);
		size = strlen(chFinded);
	} while (size > 4); //s'il y a encore des aretes a inserer ou pas

	chFinded = NULL;

	return RES_OK;
}

/*******************************************************************
 *
 * Fonction 	: 	nodeLoading
 *
 * Parametres 	: 	char* fileName (le nom du fichier de texte)
 *	 	 				Graphe* G (le pointeur sur le graphe)
 *
 * Retour 	:	    err si les erreurs produisent pendant insertionSommet(..) ou bien
 * 					il y a des anomalies dans le fichier
 * 						RES_OK si le resultat est OK
 *
 * Description 	: 	permet de charger des sommets trouvés dans le fichier
 *
 * Complexité	:	O(n) - n le nombre de la ligne
 *
 */

int nodeLoading(char* fileName, Graphe* G) {

	int err;
	int sommet;
	char* line = NULL;
	line = (char*) malloc(TAILLE_MAX * sizeof(char));
	FILE* fichier = NULL;

	// on ouvre le fichier
	fichier = fopen(fileName, "r");

	// si le fichier existe
	if (fichier != NULL) {
		//Tant que l'on n'est pas arrive fin du fichier, on prend une ligne
		while (fgets(line, TAILLE_MAX, fichier) != NULL) {

			// verification sur le premier l'indice de la ligne
			switch (findFirstElement(line)) {

			case '#':
				break; // on ne prend pas en compte des commentaires(la ligne commence par #)
			case '\n':
				break; // on ne prend pas en compte des retours a la lignes
			case 13:
				break; // on ne prend pas en compte des retours chariot
			default:
				if (strchr(line, ':') != NULL) {
					err = EdgeVertexLineVerification(line);
					if (err != RES_OK) {
						return err;
					}
					sommet = stringToInt(line, 0, ':');
					err = insertionSommet(G, sommet);
					if (err != RES_OK) {
						return err;
					}
				}
				break;
			}

		}
		// on ferme le fichier
		fclose(fichier);
	}
	free(line);
	line = NULL;
	return RES_OK;

}

/*******************************************************************
 *
 * Fonction 	: 	fileLoading
 *
 * Parametres 	: 	char* fileName (le nom du fichier de texte)
 *	 					Graphe* G (le pointeur sur le graphe)
 *
 * Retour 	:	    err si les erreurs produisent pendant creation(..) ou bien
 * 					il y a des anomalies dans le fichier
 * 						RES_OK si le resultat est OK
 *
 * Description 	: 	permet de charger le fichier
 *
 * Complexité	:	O(n) - n le nombre de la ligne
 *
 */

int fileLoading(char* fileName, Graphe** G) {

	int err;
	int i = 0;
	FILE* fichier = NULL;
	char* line = NULL;
	line = (char*) malloc(TAILLE_MAX * sizeof(char));
	int nombreDeSommet = 0;

	// on ouvre le fichier
	fichier = fopen(fileName, "r");

	// si le fichier existe
	if (fichier != NULL) {
		// On lit le fichier tant qu'on n'est pas arrive fin du fichier
		while (fgets(line, TAILLE_MAX, fichier) != NULL) {
			// verification sur le premier l'indice de la ligne
			switch (findFirstElement(line)) {
			case '#':
				break; // on ne prend pas en compte des commentaires (la ligne commence par #)
			case '\n':
				break; // on ne prend pas en compte des retours a la lignes
			case 13:
				break; // si la ligne commence par le retour chariot
			default:

				// si on n'est pas encore cree la graphe c-v-d nombre maximum de sommets est 0
				if (nombreDeSommet == 0) {

					// on lance une verification sur la ligne nombre maximum de sommets
					err = maxVertexLineVerification(line);
					if (err != RES_OK) {
						return err;
					}

					// on convert nombre maximum de sommets trouve en chaine de caractere à l'entier
					nombreDeSommet = stringToInt(line, 0, '\n');

					// le creation de la graphe
					err = creation(G, nombreDeSommet);
					if (err != RES_OK) {
						return err;
					}

					// insertion des sommets trouves dans la fichier
					err = nodeLoading(fileName, *G);
					if (err != RES_OK) {
						return err;
					}
				} else {

					// insertion des aretes trouvees dans le fichier
					err = edgeLoading(line, *G);
					if (err != RES_OK) {
						return err;
					}
				}
				break;
			}
			i++;
		}

		// on ferme le fichier
		fclose(fichier);
	}

	free(line);
	line = NULL;

	return RES_OK;
}

